home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C++ / Snippets / SuperSplash 1.0d1 / sources / •AZN_SUPER_SPLASH / JPEGUtilities ƒ / JPEGUtilities.c next >
Text File  |  1996-07-07  |  17KB  |  451 lines

  1. //=====================================================================================
  2. // JPEGUtilities.c -- written by Aaron Giles
  3. // Last update: 7/7/94
  4. //=====================================================================================
  5. // A source code library for performing very simple operations (drawing, embedding into
  6. // PICTs, and extracting from PICTs) on JPEG-compressed images using QuickTime.
  7. //=====================================================================================
  8. // This code has been successfully compiled under Metrowerks C/C++ 1.0a4, under
  9. // THINK C 7.0, and under MPW C 3.3.
  10. //=====================================================================================
  11. // If you find any bugs in this source code, please email me and I will attempt to fix
  12. // them.  If you have any additions/modifications that you think would be generally
  13. // useful, email those to me as well, and I will consider incorporating them into the
  14. // next release.  My email address is giles@med.cornell.edu.
  15. //=====================================================================================
  16. // This source code is copyright © 1994, Aaron Giles.  Permission to use this code in
  17. // your product is freely granted, provided that you credit me appropriately in your
  18. // application's About box/credits *and* documentation.  If you ship an application
  19. // which uses this code, I would also like to request that you provide me with one
  20. // complimentary copy of the application.
  21. //=====================================================================================
  22.  
  23. //=====================================================================================
  24. // Generic includes for Macintosh headers
  25. //=====================================================================================
  26.  
  27. #include <Errors.h>
  28.  
  29. //    Needed for Metrowerks CW6 to enable '#pragma unused' directive used below
  30. #define    applec
  31.  
  32.  
  33. //=====================================================================================
  34. // Includes specific to this module
  35. //=====================================================================================
  36.  
  37. #include "JPEGUtilities.h"
  38.  
  39. //=====================================================================================
  40. // Global variables local to this module
  41. //=====================================================================================
  42.  
  43. static Handle gJPEGDestHandle;
  44. static StdPixUPP gUnwrapPixProc = nil;
  45. static QDBitsUPP gDummyBitsProc;
  46. static QDTextUPP gDummyTextProc;
  47. static QDLineUPP gDummyLineProc;
  48. static QDRectUPP gDummyRectProc;
  49. static QDRRectUPP gDummyRRectProc;
  50. static QDOvalUPP gDummyOvalProc;
  51. static QDArcUPP gDummyArcProc;
  52. static QDPolyUPP gDummyPolyProc;
  53. static QDRgnUPP gDummyRgnProc;
  54.  
  55. //=====================================================================================
  56. // Prototypes for functions local to this module
  57. //=====================================================================================
  58.  
  59. static void InitJPEGUPPs(void);
  60. static unsigned char *GetJPEGData(unsigned char *theAdr, long theLen, unsigned char theCode);
  61. static OSErr MakeJPEGImageDesc(Handle theHandle, ImageDescriptionHandle theDesc);
  62. static pascal void UnwrapPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix,
  63.             short mode, RgnHandle mask, PixMap *matte, Rect *matteRect, 
  64.             short callOldBits);
  65. static pascal void DummyBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode, 
  66.             RgnHandle mask);
  67. static pascal void DummyTextProc(short count, const void *textAddr, Point numer,
  68.             Point denom);
  69. static pascal void DummyLineProc(Point newPt);
  70. static pascal void DummyRectProc(GrafVerb verb, const Rect *r);
  71. static pascal void DummyRRectProc(GrafVerb verb, const Rect *r, short ovalWidth, 
  72.             short ovalHeight);
  73. static pascal void DummyOvalProc(GrafVerb verb, const Rect *r);
  74. static pascal void DummyArcProc(GrafVerb verb, const Rect *r, short startAngle,
  75.             short arcAngle);
  76. static pascal void DummyPolyProc(GrafVerb verb, PolyHandle poly);
  77. static pascal void DummyRgnProc(GrafVerb verb, RgnHandle rgn);
  78.  
  79. //=====================================================================================
  80. // OSErr GetJPEGBounds(Handle theHandle, Rect *theBounds)
  81. //=====================================================================================
  82. // Scans the JPEG image data in theHandle for the bounding rectangle, and returns the
  83. // result in theBounds.  If the code specifying the bounds of the image was not found,
  84. // this function returns codecBadDataErr.
  85. //=====================================================================================
  86.  
  87. extern OSErr GetJPEGBounds(Handle theHandle, Rect *theBounds)
  88. {
  89.     long theLen = GetHandleSize(theHandle);
  90.     unsigned char *theData;
  91.     short theCode;
  92.     
  93.     for (theCode = 0xc0; theCode < 0xd0; theCode++)
  94.         {
  95.         theData = GetJPEGData((unsigned char *)*theHandle, theLen, theCode);
  96.         if ( theData )
  97.             break;
  98.         }
  99.     if (theCode == 0xd0) return codecBadDataErr;
  100.     theBounds->top = theBounds->left = 0;
  101.     theBounds->right = (theData[3] << 8) + theData[4];
  102.     theBounds->bottom = (theData[1] << 8) + theData[2];
  103.     return noErr;
  104. }
  105.  
  106. //=====================================================================================
  107. // OSErr DrawJPEG(Handle theHandle, Rect *srcRect, Rect *dstRect, short tMode)
  108. //=====================================================================================
  109. // Draws a JPEG image, whose data is in theHandle, to the current port.  The portion of
  110. // the image to be drawn is specified in srcRect, and any scaling or translation can be
  111. // specified through dstRect.  The transfer mode for drawing is given in the tMode
  112. // parameter.
  113. //=====================================================================================
  114.  
  115. extern OSErr DrawJPEG(Handle theHandle, Rect *srcRect, Rect *dstRect, short tMode)
  116. {
  117.     PixMapHandle dPixMap = GetGWorldPixMap((CGrafPtr)qd.thePort);
  118.     long theSize = GetHandleSize(theHandle);
  119.     char hState = HGetState(theHandle);
  120.     ImageDescriptionHandle theDesc;
  121.     MatrixRecord theMatrix;
  122.     OSErr theErr;
  123.  
  124.     theDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  125.     if ( theDesc )
  126.         {
  127.         HLock((Handle)theDesc);
  128.         theErr = MakeJPEGImageDesc(theHandle, theDesc);
  129.         if (theErr == noErr) {
  130.             SetIdentityMatrix(&theMatrix);
  131.             MapMatrix(&theMatrix, srcRect, dstRect);
  132.             HLock(theHandle);
  133.             theErr = FDecompressImage(StripAddress(*theHandle), theDesc, dPixMap,
  134.                         srcRect, &theMatrix, tMode, qd.thePort->visRgn, nil, nil,
  135.                         codecMaxQuality, anyCodec, theSize, nil, nil);
  136.             HSetState(theHandle, hState);
  137.         }
  138.         DisposeHandle((Handle)theDesc);
  139.     } else theErr = memFullErr;
  140.     return theErr;
  141. }
  142.  
  143. //=====================================================================================
  144. // Handle UnwrapJPEG(Handle srcHandle)
  145. //=====================================================================================
  146. // Extracts (unwraps) the original JPEG data from a JPEG PICT image specified in
  147. // srcHandle.  If this function fails, it returns a nil handle.
  148. //=====================================================================================
  149.  
  150. extern Handle UnwrapJPEG(PicHandle srcHandle)
  151. {
  152.     long theSize = GetHandleSize((Handle)srcHandle);
  153.     char hState = HGetState((Handle)srcHandle);
  154.     Rect bounds = (*srcHandle)->picFrame;
  155.     CGrafPort tempPort;
  156.     CQDProcs theProcs;
  157.     GrafPtr oldPort;
  158.  
  159.     gJPEGDestHandle = nil;
  160.     HLockHi((Handle)srcHandle);
  161.     GetPort(&oldPort);
  162.     OpenCPort(&tempPort);
  163.     SetPort((GrafPtr)&tempPort);
  164.     SetStdCProcs(&theProcs);
  165.     if (!gUnwrapPixProc) InitJPEGUPPs();
  166.     theProcs.newProc1 = (UniversalProcPtr)gUnwrapPixProc;
  167.     theProcs.bitsProc = gDummyBitsProc;
  168.     theProcs.textProc = gDummyTextProc;
  169.     theProcs.lineProc = gDummyLineProc;
  170.     theProcs.rectProc = gDummyRectProc;
  171.     theProcs.rRectProc = gDummyRRectProc;
  172.     theProcs.ovalProc = gDummyOvalProc;
  173.     theProcs.arcProc = gDummyArcProc;
  174.     theProcs.polyProc = gDummyPolyProc;
  175.     theProcs.rgnProc = gDummyRgnProc;
  176.     tempPort.grafProcs = &theProcs;
  177.     DrawPicture(srcHandle, &bounds);
  178.     SetPort(oldPort);
  179.     CloseCPort(&tempPort);
  180.     HSetState((Handle)srcHandle, hState);
  181.     return gJPEGDestHandle;
  182. }
  183.  
  184. //=====================================================================================
  185. // Handle WrapJPEG(Handle srcHandle)
  186. //=====================================================================================
  187. // Wraps a JPEG image into a PICT.  If this function fails, it returns a nil handle.
  188. //=====================================================================================
  189.  
  190. extern PicHandle WrapJPEG(Handle srcHandle)
  191. {
  192.     long theSize = GetHandleSize(srcHandle);
  193.     char hState = HGetState(srcHandle);
  194.     ImageDescriptionHandle theDesc;
  195.     OpenCPicParams theParams;
  196.     PicHandle theHandle;
  197.     CGrafPort tempPort;
  198.     GrafPtr oldPort;
  199.     OSErr theErr;
  200.  
  201.     HLock(srcHandle);
  202.     theDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  203.     if ( theDesc )
  204.      {
  205.         theErr = MakeJPEGImageDesc(srcHandle, theDesc);
  206.         if (theErr == noErr) {
  207.             theParams.srcRect.top = theParams.srcRect.left = 0;
  208.             theParams.srcRect.right = (*theDesc)->width;
  209.             theParams.srcRect.bottom = (*theDesc)->height;
  210.             theParams.hRes = (*theDesc)->hRes;
  211.             theParams.vRes = (*theDesc)->vRes;
  212.             theParams.version = -2;
  213.             theParams.reserved1 = theParams.reserved2 = 0;
  214.             GetPort(&oldPort);
  215.             OpenCPort(&tempPort);
  216.             SetPort((GrafPtr)&tempPort);
  217.             ClipRect(&theParams.srcRect);
  218.             
  219.             theHandle = OpenCPicture(&theParams);
  220.             if ( theHandle )
  221.                  {
  222.                 theErr = FDecompressImage(StripAddress(*srcHandle), theDesc, 
  223.                             GetGWorldPixMap(&tempPort), &theParams.srcRect, nil, ditherCopy,
  224.                             nil, nil, nil, codecMaxQuality, anyCodec, theSize, nil, nil);
  225.                 ClosePicture();
  226.                 if (theErr == noErr && !EmptyRect(&(*(PicHandle)theHandle)->picFrame)) {
  227.                     CloseCPort(&tempPort);
  228.                     SetPort(oldPort);
  229.                     DisposeHandle((Handle)theDesc);
  230.                     HSetState(srcHandle, hState);
  231.                     return theHandle;
  232.                 }
  233.                 DisposeHandle((Handle)theHandle);
  234.             } else theErr = memFullErr;
  235.             CloseCPort(&tempPort);
  236.             SetPort(oldPort);
  237.         }
  238.         DisposeHandle((Handle)theDesc);
  239.     } else theErr = memFullErr;
  240.     HSetState(srcHandle, hState);
  241.     return nil;
  242. }
  243.  
  244. //=====================================================================================
  245. // void InitJPEGUPPs(void)
  246. //=====================================================================================
  247. // Initializes all the local UPPs for the JPEG callbacks.
  248. //=====================================================================================
  249.  
  250. static void InitJPEGUPPs(void)
  251. {
  252.     gUnwrapPixProc = NewStdPixProc((ProcPtr)UnwrapPixProc);
  253.     gDummyBitsProc = NewQDBitsProc((ProcPtr)DummyBitsProc);
  254.     gDummyTextProc = NewQDTextProc((ProcPtr)DummyTextProc);
  255.     gDummyLineProc = NewQDLineProc((ProcPtr)DummyLineProc);
  256.     gDummyRectProc = NewQDRectProc((ProcPtr)DummyRectProc);
  257.     gDummyRRectProc = NewQDRRectProc((ProcPtr)DummyRRectProc);
  258.     gDummyOvalProc = NewQDOvalProc((ProcPtr)DummyOvalProc);
  259.     gDummyArcProc = NewQDArcProc((ProcPtr)DummyArcProc);
  260.     gDummyPolyProc = NewQDPolyProc((ProcPtr)DummyPolyProc);
  261.     gDummyRgnProc = NewQDRgnProc((ProcPtr)DummyRgnProc);
  262. }
  263.  
  264. //=====================================================================================
  265. // unsigned char *GetJPEGData(unsigned char *theAdr, long theLen, unsigned char theCode)
  266. //=====================================================================================
  267. // Returns the address of the specified marker within the JPEG data stream.
  268. //=====================================================================================
  269.  
  270. static unsigned char *GetJPEGData(unsigned char *theAdr, long theLen, unsigned char theCode) 
  271. {
  272.     unsigned char *theEnd = theAdr + theLen;
  273.     long theSize;
  274.     
  275.     while (true) {
  276.         while (*theAdr++ != 0xff && theAdr < theEnd)
  277.             NULL;
  278.         if (theAdr >= theEnd) return nil;
  279.         while (*theAdr == 0xff) theAdr++;
  280.         if (theAdr >= theEnd) return nil;
  281.         if (*theAdr == theCode) break;
  282.         else if (*theAdr == 0xd9) return nil;
  283.         else if (*theAdr <= 0x01 || (*theAdr >= 0xd0 && *theAdr <= 0xd8)) {
  284.             theAdr++;
  285.             continue;
  286.         }
  287.         theAdr++;
  288.         if ((theSize = (*theAdr << 8) + *(theAdr + 1)) < 0) return nil;
  289.         if ((theAdr + theSize) >= theEnd) {
  290.             *(theAdr - 1) = 0xd9;
  291.             return nil;
  292.         } else theAdr += theSize;
  293.     }
  294.     theAdr += 3;
  295.     return theAdr;
  296. }
  297.  
  298. //=====================================================================================
  299. // OSErr MakeJPEGImageDesc(Handle theHandle, ImageDescriptionHandle theDesc)
  300. //=====================================================================================
  301. // Creates a QuickTime image description record based on JPEG data.
  302. //=====================================================================================
  303.  
  304. static OSErr MakeJPEGImageDesc(Handle theHandle, ImageDescriptionHandle theDesc) 
  305. {
  306.     CodecInfo theInfo;
  307.     OSErr theErr;
  308.     Rect bounds;
  309.     
  310.     theErr = GetCodecInfo(&theInfo, 'jpeg', anyCodec);
  311.     if (theErr != noErr) return theErr;
  312.     theErr = GetJPEGBounds(theHandle, &bounds);
  313.     if (theErr != noErr) return theErr;
  314.     (*theDesc)->idSize = sizeof(ImageDescription);
  315.     (*theDesc)->cType = 'jpeg';
  316.     (*theDesc)->resvd1 = (*theDesc)->resvd2 = (*theDesc)->dataRefIndex = 0;
  317.     BlockMove(theInfo.typeName, (*theDesc)->name, 32);
  318.     (*theDesc)->version = theInfo.version;
  319.     (*theDesc)->revisionLevel = theInfo.revisionLevel;
  320.     (*theDesc)->vendor = theInfo.vendor;
  321.     (*theDesc)->temporalQuality = 0;
  322.     (*theDesc)->spatialQuality = 0x200L;
  323.     (*theDesc)->width = bounds.right;
  324.     (*theDesc)->height = bounds.bottom;
  325.     (*theDesc)->hRes = (*theDesc)->vRes = 0x480000L;
  326.     (*theDesc)->dataSize = GetHandleSize(theHandle);
  327.     (*theDesc)->frameCount = 1;
  328.     (*theDesc)->depth = 32;
  329.     (*theDesc)->clutID = -1;
  330.     return theErr;
  331. }
  332.  
  333. //=====================================================================================
  334. // pascal void UnwrapPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix,
  335. //            short mode, RgnHandle mask, PixMap *matte, Rect *matteRect,
  336. //            short callOldBits)
  337. //=====================================================================================
  338. // Bottleneck function called to extract raw JPEG data from an image.
  339. //=====================================================================================
  340.  
  341. static pascal void UnwrapPixProc(PixMap *src, Rect *srcRect, MatrixRecord *matrix,
  342.             short mode, RgnHandle mask, PixMap *matte, Rect *matteRect,
  343.             short callOldBits)
  344. {
  345. #ifdef applec
  346. #pragma unused(srcRect, matrix, mode, mask, matte, matteRect, callOldBits)
  347. #endif
  348.     long bufSize, left, offset = 0;
  349.     ImageDescriptionHandle theDesc;
  350.     ICMProgressProcRecord progProc;
  351.     ICMDataProcRecord dataProc;
  352.     Ptr theData, destAdr;
  353.     
  354.     if (!GetCompressedPixMapInfo(src, &theDesc, &theData, &bufSize, &dataProc, &progProc)) {
  355.         if ((*theDesc)->cType == 'jpeg' && !gJPEGDestHandle)
  356.          {
  357.             gJPEGDestHandle = NewHandle((*theDesc)->dataSize);
  358.             if ( gJPEGDestHandle )
  359.              {
  360.                 HLock(gJPEGDestHandle);
  361.                 destAdr = (Ptr)*gJPEGDestHandle;
  362.                 left = (*theDesc)->dataSize;
  363.                 if (dataProc.dataProc) {
  364.                     while (left > bufSize) {
  365.                         BlockMove(theData, &destAdr[offset], bufSize);
  366.                         offset += bufSize;
  367.                         left -= bufSize;
  368.                         theData += bufSize;
  369.                         if (CallICMDataProc(dataProc.dataProc, &theData, 
  370.                                     (left > bufSize) ? bufSize : left, 
  371.                                     dataProc.dataRefCon)) return;
  372.                     }
  373.                 }
  374.                 BlockMove(theData, &destAdr[offset], left);
  375.                 HUnlock(gJPEGDestHandle);
  376.             }
  377.         }
  378.     }
  379. }
  380.  
  381. //=====================================================================================
  382. // Dummy QuickDraw bottlenecks to filter out non-PixMaps within PICTs
  383. //=====================================================================================
  384.  
  385. static pascal void DummyBitsProc(PixMap *src, Rect *srcRect, Rect *dstRect, short mode, 
  386.             RgnHandle mask) 
  387. {
  388. #ifdef applec
  389. #pragma unused(src, srcRect, dstRect, mode, mask)
  390. #endif
  391. }
  392.  
  393. static pascal void DummyTextProc(short count, const void *textAddr, Point numer,
  394.             Point denom) 
  395. {
  396. #ifdef applec
  397. #pragma unused(count, textAddr, numer, denom)
  398. #endif
  399. }
  400.  
  401. static pascal void DummyLineProc(Point newPt)
  402. {
  403. #ifdef applec
  404. #pragma unused(newPt)
  405. #endif
  406. }
  407.  
  408. static pascal void DummyRectProc(GrafVerb verb, const Rect *r)
  409. {
  410. #ifdef applec
  411. #pragma unused(verb, r)
  412. #endif
  413. }
  414.  
  415. static pascal void DummyRRectProc(GrafVerb verb, const Rect *r, short ovalWidth, 
  416.     short ovalHeight)
  417. {
  418. #ifdef applec
  419. #pragma unused(verb, r, ovalWidth, ovalHeight)
  420. #endif
  421. }
  422.  
  423. static pascal void DummyOvalProc(GrafVerb verb, const Rect *r)
  424. {
  425. #ifdef applec
  426. #pragma unused(verb, r)
  427. #endif
  428. }
  429.  
  430. static pascal void DummyArcProc(GrafVerb verb, const Rect *r, short startAngle,
  431.             short arcAngle)
  432. {
  433. #ifdef applec
  434. #pragma unused(verb, r, startAngle, arcAngle)
  435. #endif
  436. }
  437.  
  438. static pascal void DummyPolyProc(GrafVerb verb, PolyHandle poly)
  439. {
  440. #ifdef applec
  441. #pragma unused(verb, poly)
  442. #endif
  443. }
  444.  
  445. static pascal void DummyRgnProc(GrafVerb verb, RgnHandle rgn)
  446. {
  447. #ifdef applec
  448. #pragma unused(verb, rgn)
  449. #endif
  450. }
  451.